package com.weaver.dev.tools.sdk.ding;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;

import com.weaver.dev.tools.StringUtils;
import com.weaver.dev.tools.http.RequestUtils;
import com.weaver.dev.tools.sdk.ding.config.DingConfig;
import com.weaver.dev.tools.sdk.ding.entity.*;
import com.weaver.tools.sdk.ding.entity.*;
import lombok.SneakyThrows;
import okhttp3.OkHttpClient;
import okhttp3.Response;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 钉钉接口API封装
 */
public class DingSdk {

    private String appKey;

    private String appSecret;

    private DingConfig dingConfig;

    private OkHttpClient client;

    private Cache<String, String> cache = CacheBuilder.newBuilder()
            .maximumSize(1)
            .expireAfterWrite(6900, TimeUnit.SECONDS)
            .build();

    public DingSdk(String appKey, String appSecret) {
        this(appKey, appSecret, new DingConfig(), new OkHttpClient());
    }

    public DingSdk(String appKey, String appSecret, OkHttpClient client) {
        this(appKey, appSecret, new DingConfig(), client);
    }

    public DingSdk(String appKey, String appSecret, DingConfig dingConfig) {
        this(appKey, appSecret, dingConfig, new OkHttpClient());
    }


    public DingSdk(String appKey, String appSecret, DingConfig dingConfig, OkHttpClient client) {
        this(appKey, appSecret, true, dingConfig, client);
    }

    public DingSdk(String appKey, String appSecret, boolean isLazy, DingConfig dingConfig, OkHttpClient client) {
        this.appKey = appKey;
        this.appSecret = appSecret;
        this.dingConfig = dingConfig;
        this.client = client;
        if (!isLazy) {
            try {
                accessToken();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("构建失败： " + e.getMessage());
            }
        }
    }

    public void setAccessToken(String token) {
        this.cache.put("token", token);
    }

    public Response requestAccessToken() throws IOException {
        Map<String, String> params = Maps.newHashMap();
        params.put("appkey", appKey);
        params.put("appsecret", appSecret);
        return RequestUtils.doGetWithoutChange(this.client,this.dingConfig.getAccessTokenUrl(), params);
    }

    private Map<String, Object> getTokenMap() throws IOException {
        Response tokenRes = requestAccessToken();
        if (tokenRes.isSuccessful()) {
            JSONObject res = JSON.parseObject(tokenRes.body().string());
//            {"errcode":0,"access_token":"aeae5f19041a352fb093b40332bdef62","errmsg":"ok","expires_in":7200}
            if (StringUtils.equals(res.getString("errcode"), "0")) {
                String token = res.getString("access_token");
                long expiresTime = res.getLong("expires_in");
                Map<String, Object> resMap = Maps.newHashMap();
                resMap.put("token", token);
                resMap.put("time", expiresTime);
                return resMap;
            } else {
                throw new RuntimeException("获取token请求失败：" + res.getString("errmsg"));
            }
        } else {
            throw new RuntimeException("获取token请求异常: " + tokenRes.body().string());

        }
    }

    /**
     * 获取当前的access_token
     * @return
     */
    public String accessToken() throws ExecutionException, IOException {
        if (Objects.isNull(cache)) { // 如果是第一次，则构建缓存
            Map<String, Object> resMap = getTokenMap();
            this.cache = CacheBuilder.newBuilder()
                    .maximumSize(1)
                    .expireAfterWrite(Long.parseLong(Objects.requireNonNull(StringUtils.val(resMap.get("time")))) - 300, TimeUnit.MINUTES)
                    .build();
            this.cache.put("token", Objects.requireNonNull(StringUtils.val(resMap.get("token"))));
        }
        return cache.get("token", () -> StringUtils.val(getTokenMap().get("token")));
    }

    public DingMessageResult sendCorpMessage(DingSendCorpMessageParam param) throws IOException, ExecutionException {

        Map<String, Object> mapParams = Maps.newHashMap();
        mapParams.put("agent_id", param.getAgentId());
        mapParams.put("userid_list", param.getUseridList());
        mapParams.put("dept_id_list", param.getDeptIdList());
        mapParams.put("to_all_user", param.isToAllUser());
        mapParams.put("msg", param.getMsg());

        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getSendCorpMessageUrl() + "?access_token=" + accessToken(), mapParams);
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            return JSON.parseObject(bodyStr, DingMessageResult.class);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }

    public DingBlackboardResult createBlackboard(DingBlackboardParam param) throws IOException, ExecutionException {
        Map<String, Object> mapParams = Maps.newHashMap();
        Map<String, Object> paramTemp = Maps.newHashMap();
        paramTemp.put("operation_userid", param.getOperation_userid());
        paramTemp.put("author", param.getAuthor());
        paramTemp.put("private_level", param.getPrivate_level());
        paramTemp.put("ding", param.getDing());
        paramTemp.put("blackboard_receiver", param.getBlackboard_receiver());
        paramTemp.put("title", param.getTitle());
        paramTemp.put("push_top", param.getPush_top());
        paramTemp.put("content", param.getContent());
        paramTemp.put("category_id", param.getCategory_id());
        paramTemp.put("coverpic_mediaid", param.getCoverpic_mediaid());

        mapParams.put("create_request", paramTemp);
        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getCreateBlackboardUrl() + "?access_token=" + accessToken(), mapParams);
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            return JSON.parseObject(bodyStr, DingBlackboardResult.class);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }

    public DingTaskResult createTask(String unionId, String operatorId, DingTaskParam param) throws IOException, ExecutionException {
        Map<String, Object> mapParams = Maps.newHashMap();

        mapParams.put("sourceId", param.getSourceId());
        mapParams.put("subject", param.getSubject());
        mapParams.put("creatorId", param.getCreatorId());
        mapParams.put("description", param.getDescription());
        mapParams.put("dueTime", param.getDueTime());
        mapParams.put("executorIds", param.getExecutorIds());
        mapParams.put("participantIds", param.getParticipantIds());
        mapParams.put("detailUrl", param.getDetailUrl());
        mapParams.put("isOnlyShowExecutor", param.getIsOnlyShowExecutor());
        mapParams.put("priority", param.getPriority());
        mapParams.put("notifyConfigs", param.getNotifyConfigs());
        Map<String, String> headers = Maps.newHashMap();
        headers.put("x-acs-dingtalk-access-token", accessToken());
        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getAddTodoTaskUrl(unionId), headers, mapParams);
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            System.out.println(bodyStr);
            return JSON.parseObject(bodyStr, DingTaskResult.class);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }


    public DingVideoMeetingResult createVideoMeeting(DingVideoMeetingParam param) throws IOException, ExecutionException {
        Map<String, Object> mapParams = Maps.newHashMap();

        mapParams.put("userId", param.getUserId());
        mapParams.put("confTitle", param.getConfTitle());
        mapParams.put("inviteUserIds", param.getInviteUserIds());
        mapParams.put("inviteCaller", param.getInviteCaller());

        Map<String, String> headers = Maps.newHashMap();
        headers.put("x-acs-dingtalk-access-token", accessToken());
        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getCreateVideoMeetingUrl(), headers, mapParams);
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            return JSON.parseObject(bodyStr, DingVideoMeetingResult.class);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }

    @SneakyThrows
    public DingAttendResult attendUpload(DingAttendUploadParam param) {
        Map<String, Object> mapParams = Maps.newHashMap();

        mapParams.put("userid", param.getUserid());
        mapParams.put("device_name", param.getDeviceName());
        mapParams.put("device_id", param.getDeviceId());
        mapParams.put("photo_url", param.getPhotoUrl());
        mapParams.put("user_check_time", param.getUserCheckTime());

        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getAttendUploadUrl(), mapParams);
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            return JSON.parseObject(bodyStr, DingAttendResult.class);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }

    public JSONObject createCalendar(String userId, String calendarId, DingCalendarCreateParam param) throws IOException, ExecutionException {
        JSONObject params = JSONObject.parseObject(JSON.toJSONString(param));
        Map<String, String> headers = Maps.newHashMap();
        headers.put("x-acs-dingtalk-access-token", accessToken());
        Response response = RequestUtils.doPostByJson(client,
                dingConfig.getCreateCalendarUrl(userId, calendarId), headers, params.getInnerMap());
        if (response.isSuccessful()) {
            String bodyStr = response.body().string();
            return JSONObject.parseObject(bodyStr);
        } else {
            throw new RuntimeException("请求异常: " + response.body().string());
        }
    }


    public static void main(String[] args) throws IOException, ExecutionException {
        String corpId = "dingdab9542b79c076e7a39a90f97fcb1e09";
        String apiToken = "eb0289c093a13c90ac7959a02d22999f";

//        String agentId = "1179323730";
//        String appKey = "dingsqro09fdhd7icqaj";
//        String appSecret = "LAImoB9JP-i5ReqXiTly_IGna8Gj0aGx87d4C7eSwEl-KYIlpU9dlJwzFPR_oMrO";
        String agentId = "1730555503";
        String appKey = "ding1ukahahbqwackydf";
        String appSecret = "lShQmm7wiHSZq7QJQ3_bKTrbIeJ14cvb0XGLhgqpWadayC6T07VcACFT6tcXKJEm";

        DingSdk dingSdk = new DingSdk(appKey, appSecret);
        dingSdk.setAccessToken("d41e64b83b973ac09d95e507c5ae9343");
        System.out.println(dingSdk.accessToken());

        DingSendCorpMessageParam param = new DingSendCorpMessageParam();
        param.setAgentId(agentId);
        param.setToAllUser(true);
        JSONObject obj = new JSONObject();
        obj.put("msgtype", "link");
        JSONObject linkObj = new JSONObject();
        linkObj.put("messageUrl", "https://weapp.eteams.cn"); // 链接地址
        linkObj.put("picUrl", "@lALPDfmVSmn-ig3NAQfNAdg"); // 链接地址
        linkObj.put("title", "会议通知");
        linkObj.put("text", "消息体");
        obj.put("link", linkObj);
        param.setMsg(obj);
        DingMessageResult dingMessageResult = dingSdk.sendCorpMessage(param);
        System.out.println(dingMessageResult);


    }

}
